import React, {
  useState,
  ChangeEvent,
  ReactElement,
  useEffect,
  KeyboardEvent,
  useRef,
} from "react";
import { Input, InputProps } from "../Input/input";
import classNames from "classnames";
import Icon from "../Icon/Icon";
import useDebounced from "../../hooks/useDebounce";
import useClickOutside from "../../hooks/useClickOutside";
export interface AutoCompleteProps extends Omit<InputProps, "onSelect"> {
  fetchSuggestions: (
    str: string
  ) => DataSourceType[] | Promise<DataSourceType[]>;
  onSelect?: (item: DataSourceType) => void;
  renderOption?: (item: DataSourceType) => ReactElement;
}
export interface DataSourceObject {
  value: string;
  number: number;
}

export type DataSourceType<T = {}> = T & DataSourceObject;
export const AutoComplete = (props: AutoCompleteProps) => {
  const { fetchSuggestions, onSelect, renderOption, value, ...restProps } =
    props;
  const [inputValue, setinputValue] = useState(value as string);
  const [suggestions, setsuggestions] = useState<DataSourceType[]>([]);
  const [loading, setloading] = useState(false);
  const [highLightIndex, setHighLightIndex] = useState(-1);
  const triggerSearch = useRef(false);
  const componentRef = useRef<HTMLDivElement>(null);
  const debouncedValue = useDebounced(inputValue, 500);
  useClickOutside(componentRef, () => {
    setsuggestions([]);
  });
  useEffect(() => {
    if (debouncedValue && triggerSearch.current) {
      const result = fetchSuggestions(debouncedValue);
      if (result instanceof Promise) {
        setloading(true);
        result.then((data) => {
          setloading(false);
          setsuggestions(data);
        });
      } else {
        setsuggestions(result);
      }
    } else {
      setsuggestions([]);
    }
    setHighLightIndex(-1);
  }, [debouncedValue, fetchSuggestions]);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value.trim();
    setinputValue(value);
    triggerSearch.current = true;
  };
  const generateDropdown = () => {
    return (
      <ul>
        {suggestions.map((item, index) => {
          const cnames = classNames("suggestion-item", {
            "item-highlighted": index === highLightIndex,
          });
          return (
            <li
              key={index}
              onClick={() => {
                handleSelect(item);
              }}
              className={cnames}
            >
              {renderTemplate(item)}
            </li>
          );
        })}
      </ul>
    );
  };
  const handleSelect = (item: DataSourceType) => {
    setinputValue(item.value);
    setsuggestions([]);
    if (onSelect) {
      onSelect(item);
    }
    triggerSearch.current = false;
  };
  const renderTemplate = (item: DataSourceType) => {
    return renderOption ? renderOption(item) : item.value;
  };
  const highLight = (index: number) => {
    if (index < 0) index = 0;
    if (index >= suggestions.length) index = suggestions.length - 1;
    setHighLightIndex(index);
  };
  const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
    switch (e.code) {
      case "Enter":
        if (suggestions[highLightIndex])
          handleSelect(suggestions[highLightIndex]);
        break;
      case "ArrowDown":
        highLight(highLightIndex + 1);
        break;
      case "ArrowUp":
        highLight(highLightIndex - 1);
        break;
      default:
        break;
    }
  };
  return (
    <div className="coerger-auto-complete" ref={componentRef}>
      <Input
        value={inputValue}
        onChange={handleChange}
        {...restProps}
        onKeyDown={handleKeyDown}
      ></Input>
      {loading && (
        <ul>
          <Icon icon="spinner" spin></Icon>
        </ul>
      )}
      {suggestions.length > 0 && generateDropdown()}
    </div>
  );
};
